#pragma once

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <vector>
#include <string>
#include "InetAddr.hpp"
#include "ThreadPool.hpp"
#include "LockGuard.hpp"

using func = std::function<void()>;

class Route
{
public:
    Route()
    {
        pthread_mutex_init(&_mutex, nullptr);
    }

    ~Route()
    {
        pthread_mutex_destroy(&_mutex);
    }

    void CheckUser(const InetAddr& user)
    {
        LockGuard lock(&_mutex);
        for(auto& e : _online_user)
        {
            if(e == user)
            {
                return;
            }
        }
        _online_user.emplace_back(user);
        LOG(INFO, "[%s] enter success\n", user.Ip().c_str());
    }

    void Offline_user(const InetAddr& user)
    {
        LockGuard lock(&_mutex);
        std::vector<InetAddr>::iterator it = _online_user.begin(); 
        for(; it != _online_user.end(); it++)
        {
            if(*it == user)
            {
                _online_user.erase(it);
            }
        }
    }

    // 将数据转发给除了发送数据的客户端以外的所有在线客户端
    // 发送给别人的数据会显示对应的ip和端口
    // 比如说：[ip][port]#
    void ForwardHelper(const int& sockfd,const InetAddr& user, const std::string& message)
    {
        std::string buff = "[" + user.Ip() + "][" + std::to_string(user.Port()) + "]#"; 
        buff += message;
        int flag = 0;
        LockGuard lock(&_mutex);
        for(auto& e : _online_user)
        {
            // if(e == user)
            // {
            //     continue;
            // }
            socklen_t len = sizeof(e.Addr());
            int n = sendto(sockfd, buff.c_str(), buff.size(), 0, (const struct sockaddr*)&(e.Addr()), len);
            if(n > 0)
            {
                flag = 1;
            }
        }
        if(flag == 1)
        {
            LOG(INFO, "Send message success\n");
        }
        else
        {
            LOG(INFO, "Send message failed\n");
        }
    }

    void Forward(const int& sockfd, InetAddr user, std::string message)
    {
        CheckUser(user);

        if(message == "QUIT")
        {
            Offline_user(user);
            return;
        }

        func t = std::bind(&Route::ForwardHelper, this, sockfd, user, message);
        ThreadPool<func>::GetInstance()->Equeue(t);
    }
private:
    std::vector<InetAddr> _online_user;
    pthread_mutex_t _mutex;
};